﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Practices.Unity;
using StockholmsStad.Utilities;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Windows.UI.Infrastructure.Interfaces;
using StockholmsStad.Windows.UI.Modules.Maintenance.Interfaces;
using StockholmsStad.Windows.UI.Facade;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;
using StockholmsStad.Windows.UI.Modules.Maintenance.Models;
using Microsoft.Practices.Composite.Events;

namespace StockholmsStad.Windows.UI.Modules.Maintenance.Services
{
    public class UserService : IUserService
    {
        private ObservableCollection<UserPresentationModel> users;
        private IApplicationService applicationService;

        [Dependency]
        public IApplicationService ApplicationService
        {
            set { applicationService = value; }
        }

        #region IUserService Members

        public UserPresentationModel AddNewUser()
        {
            var user = new UserPresentationModel {IsActive = true};
            user.Added += UserAdded;
            user.Saved += UserSaved;
            user.ChangedPassword += UserPasswordChanged;
            user.Deleted += UserDeleted;

            return user;
        }

        public ObservableCollection<UserPresentationModel> GetUsers(bool includeInactiveUsers)
        {
            var user = applicationService.GetCurrentUser();
            var userFacade = new UserFacade(user);
            var userList = userFacade.GetUsers(includeInactiveUsers);

            if(userList == null || userList.Count == 0)
            {
                var parvisuser = AddNewUser();
                return new ObservableCollection<UserPresentationModel> {parvisuser};
            }

            CreateUsers(userList);
            return users;
        }

        public List<UserRole> GetRoles()
        {
            var user = applicationService.GetCurrentUser();
            var userFacade = new UserFacade(user);
            return userFacade.GetRoles();
        }

        #endregion

        #region Private methods

        private void UserSaved(object sender, DataEventArgs<UserPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                UserPresentationModel user = e.Value;

                ParvisUser parvisUser = CreateParvisUser(user);
                var loggedInUser = applicationService.GetCurrentUser();
                var facade = new UserFacade(loggedInUser);

                if (user.ParvisUserId.HasValue)
                {
                    facade.UpdateUser(parvisUser);
                }
                else
                {
                    var id = facade.AddUser(parvisUser);
                    user.ParvisUserId = id;
                    users.Add(user);
                }
            }
        }

        private void UserAdded(object sender, DataEventArgs<UserPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var newUser = new UserPresentationModel();
                newUser.Saved += UserSaved;
                newUser.Deleted += UserDeleted;
                newUser.Added += UserAdded;
                newUser.ChangedPassword += UserPasswordChanged;
            }
        }

        private void UserDeleted(object sender, DataEventArgs<UserPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var user = e.Value;

                var loggedInUser = applicationService.GetCurrentUser();
                var userFacade = new UserFacade(loggedInUser);
                userFacade.DeleteUser((int) user.ParvisUserId);
                users.Remove(user);
            }
        }

        private void UserPasswordChanged(object sender, DataEventArgs<UserPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var user = e.Value;
                var loggedInUser = applicationService.GetCurrentUser();
                var userFacade = new UserFacade(loggedInUser);
                var parvisUser = CreateParvisUser(user);
                userFacade.SendForgottenPassword(parvisUser);
            }
        }

        private void CreateUsers(IEnumerable<ParvisUser> userList)
        {
            users = new ObservableCollection<UserPresentationModel>();

            foreach (var user in userList)
            {
                var model = new UserPresentationModel
                {
                    ParvisUserId = user.ParvisUserId,
                    FirstName = GetEmptyStringIfNull(user.FirstName),
                    LastName = GetEmptyStringIfNull(user.LastName),
                    PhoneNumber = GetEmptyStringIfNull(user.PhoneNumber),
                    CellPhoneNumber = GetEmptyStringIfNull(user.CellPhoneNumber),
                    UserRole = new ValueIdPair
                    {
                        Description = EnumUtility.GetEnumDescription(user.Role),
                        Id = (int)user.Role,
                        Name = Enum.GetName(typeof(UserRole), user.Role)
                    },
                    EmailAddress = GetEmptyStringIfNull(user.Username),
                    IsActive = user.IsActive
                };

                users.Add(model);

                model.Saved += UserSaved;
                model.Added += UserAdded;
                model.ChangedPassword += UserPasswordChanged;
                model.Deleted += UserDeleted;
            }
        }

        private static string GetEmptyStringIfNull(string value)
        {
            return value ?? String.Empty;
        }

        private static ParvisUser CreateParvisUser(UserPresentationModel user)
        {
            var addedUser = new ParvisUser
            {
                CellPhoneNumber = user.CellPhoneNumber,
                PhoneNumber = user.PhoneNumber,
                FirstName = user.FirstName,
                LastName = user.LastName,
                ParvisUserId = user.ParvisUserId,
                Username = user.EmailAddress,
                Role = (UserRole)Enum.ToObject(typeof(UserRole), user.UserRole.Id),
                IsActive = user.IsActive,
            };
            return addedUser;
        }

        #endregion
    }
}